#include <chrono>
#include <iostream>
#include <openssl/aes.h>
#include <openssl/evp.h>
#include <vector>

using namespace std;

const uint64_t dataLen = (uint64_t)1024 * 1024 * 4;
const int roundNum = 1;
const string key = "0123456789123456";
const string iv = "abcdefghijklmnop";

int main()
{
    string in, out;
    in.resize(dataLen);
    out.resize(dataLen + AES_BLOCK_SIZE);
    EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();

    EVP_CIPHER_CTX_init(ctx);
    auto pos1 = chrono::steady_clock::now();
    for (int i = 0; i < roundNum; i++) {
        int ret = EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), nullptr, (const unsigned char*)key.c_str(), (const unsigned char*)iv.c_str());
        int cryptoDataLen = 0;
        ret = EVP_EncryptUpdate(ctx, (unsigned char*)out.c_str(), &cryptoDataLen, (const unsigned char*)in.c_str(), in.length());
        if (ret != 1) {
            cout << "error while EVP_EncryptUpdate" << endl;
            return -1;
        }
        int flen = 0;
        ret = EVP_EncryptFinal_ex(ctx, (unsigned char*)out.c_str() + cryptoDataLen, &flen);
        if (ret != 1) {
            cout << "error while EVP_EncryptFinal_ex" << endl;
            return -1;
        }
        ret = EVP_CIPHER_CTX_cleanup(ctx);
        if (ret != 1) {
            cout << "error while EVP_CIPHER_CTX_cleanup" << endl;
            return -1;
        }
        // string res((char*)out.c_str(), cryptoDataLen + flen);
    }
    auto pos2 = chrono::steady_clock::now();
    chrono::duration<double, milli> dur1 = pos2 - pos1;
    cout << "encrypt [" << dataLen << "], cost: " << dur1.count() << " ms, thoughput: " << dataLen * 1000 / (1024 * 1024 * dur1.count()) << " MB/s" << endl;
    return 0;
}